import ReactDOM from 'react-dom';

// 存储状态的数组
let state = [];
// 存储状态更新函数的数组
let setters = [];
// 当前状态索引
let stateIndex = 0;

// 存储副作用的数组
let effects = [];
// 当前副作用索引
let effectIndex = 0;

// 创建状态更新函数
function createSetter(index) {
  return function(newState) {
    // 如果是函数形式，传入当前状态计算新状态
    if (typeof newState === 'function') {
      state[index] = newState(state[index]);
    } else {
      state[index] = newState;
    }
    // 状态更新后重新渲染
    render();
  };
}

// 模拟useState
function useState(initialState) {
  // 保存当前索引，因为后续stateIndex会变化
  const currentIndex = stateIndex;

  // 不存在
  if (!state[currentIndex]) {
    // 不存在则使用初始值
    state[currentIndex] = initialState;
    // 设置 set 函数
    setters[currentIndex] = createSetter(currentIndex);
  }

  // 准备下一个状态的索引
  stateIndex++;

  // 返回当前状态和对应的更新函数
  return [state[currentIndex], setters[currentIndex]];
}

// 模拟useEffect
function useEffect(callback, dependencies) {
  // 保存当前副作用索引
  const currentIndex = effectIndex;

  // 检查是否有依赖项变化
  const hasChanged = () => {
    // 如果没有提供依赖项数组，每次渲染都认为变化了
    if (!dependencies) return true;

    // 获取上一次的依赖项
    const prevDeps = effects[currentIndex]?.dependencies;

    // 如果是第一次执行，也认为变化了
    if (!prevDeps) return true;

    // 对比新旧依赖项是否有变化
    return dependencies.some((dep, i) => dep !== prevDeps[i]);
  };

  // 如果依赖项有变化，才执行副作用
  if (hasChanged()) {
    // 保存清理函数
    const cleanup = callback();

    // 存储当前副作用的信息：清理函数和依赖项
    effects[currentIndex] = {
      cleanup,
      dependencies: dependencies ? [...dependencies] : undefined,
    };
  }

  // 准备下一个副作用的索引
  effectIndex++;
}

// 重新渲染组件 (更新后调用)
function render() {
  // 重置索引，确保每次渲染时钩子调用顺序一致
  stateIndex = 0;
  effectIndex = 0;
  ReactDOM.render(<Comp />, document.getElementById('use-root'));
}

function Comp() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('张三');

  // 模拟副作用：当count变化时执行
  useEffect(() => {
    console.log(`count发生变化: 新值为${count}`);
    // 清理函数：组件卸载或count再次变化前执行
    return () => console.log(`清理count副作用: 旧值为${count}`);
  }, [count]);

  // 模拟副作用：当name变化时执行
  useEffect(() => {
    console.log(`name发生变化: 新值为${name}`);
    return () => console.log(`清理name副作用: 旧值为${name}`);
  }, [name]);

  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>setCount</button>
      {name}
      <button onClick={() => setName('李四')}>setName</button>
    </div>
  );
}

export default Comp;
